// HunterView.c
// Implementation of HunterViewADT
// Author(s): Alexander Saunders, Shivanth Radhakrishnan, Daniel Chen, Dylan Lai, Karn Agrawal, Robert Newey.
// TeamName: TheYellowFormPolicy
// Tutorial Group: Thursday
// Tutor: Sim
// Date: yes
// Version: 0

#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "HunterView.h"

#ifndef MESSAGE_SIZE
#include "game.h"
#endif

#define PRE_GAME_TURN -1

#define MOVE_STR_LEN 8

#define HEALTH_INIT 9
#define HEALTH_TRAP (-2)
#define HEALTH_DRACULA (-4)
#define HEALTH_REST 3

#define ENCOUNTER_TRAP 'T'
#define ENCOUNTER_DRACULA 'D'
#define NUM_ENCOUNTERS 4

#define DRAC_INIT 40
#define DRAC_FOUND (-10)
#define DRAC_SEA (-2)
#define DRAC_CASTLE 10

#define NUM_SEAS 11
#define NUM_CASTLE_LOCS 2
#define NUM_LOCATIONS 80

#define FALSE 0
#define TRUE 1

struct hunterView{
    char *pastPlays;
    playerMessage *messages;
};

///////////////////////////////////////////
/////   Helper function definitions   /////
///////////////////////////////////////////

// Returns the number of a player given a character
// Coded by: Daniel Chen, Robert Newey
int playerNumber(char name);

// Checks to see which players haven't been kicked
// Coded by: Daniel Chen, Robert Newey
void alivePlayers (HunterView hv, int isAlive[]);

// Returns the locations of all players
// Coded by: Daniel Chen, Robert Newey
void setLocations (HunterView hv, Move* moves);

// Checks if a given player has just rested
// Coded by: Daniel Chen, Robert Newey
int checkRested(HunterView hv, int player);

// Returns the health of a given player
// Coded by: Daniel Chen, Robert Newey
int checkHealth(HunterView hv, int player, int *died);

// Returns the most recently left message by a given player
// Coded by: Daniel Chen, Robert Newey
char *getMessage(HunterView hv, int player);

// Fills locations with location codes
// Coded by: Robert Newey
void populateLocationCodes(char** locations);

// Given a string, translate that into its numeric code
int locationCode(char *str);

// Given a point in the graph, BFS out from there to fill in the rail network
// Coded by: Robert Newey
void railBFS(Connection **graph, int point);

///////////////////////////////////////////
/////     ADT Interface functions     /////
///////////////////////////////////////////

// creates a HunterView
// Coded by: Dylan Lai
HunterView newHunterView (char *pastPlays, playerMessage messages[]) {
    int f;
    int numTurns = (strlen(pastPlays)+1)/MOVE_STR_LEN;

    HunterView hv = malloc (sizeof (struct hunterView));
    assert (hv != NULL);

    hv->pastPlays = malloc(sizeof(char)*(strlen(pastPlays)+1));
    strcpy(hv->pastPlays, pastPlays);

    hv->messages = malloc(sizeof(playerMessage)*numTurns);
    assert(hv->messages != NULL);

    for (f = 0; f < numTurns; f++){
        strcpy(hv->messages[f], messages[f]);
    }

    return hv;
}

// Returns all the moves since and including the current player's last move
// Coded by: Daniel Chen, Robert Newey
// Tested by: Dylan Lai
void movesSinceTurn (HunterView hv, Move* moves){
    int isAlive[NUM_HUNTERS];
    int f;
    int died;

    for (f = 0; f < NUM_HUNTERS; f++){
        moves[f]->playerNum = f;
    }

    alivePlayers (hv, isAlive);
    setLocations (hv, moves);
    for (f=0; f < NUM_HUNTERS; f++) {
        moves[f]->rested = checkRested (hv, f);
        moves[f]->health = checkHealth (hv, f, &died);
        if (died){
            moves[f]->location = locationCode("JM");
        }
        moves[f]->message = getMessage(hv, f);
        moves[f]->stillInGame = isAlive[f];
    }

}

// Returns the current player's number
// Coded by: Dylan Lai
int whoAmI (HunterView hv) {
    // Needs to be updated to allow for players to be missing
	// This is wrong. This function will give an incorrect result in the event that a player
	// Is disqualified in the middle of a round
    return turnNumber (hv) % (NUM_HUNTERS + 1);
}

// Returns the turn number
// Coded by: Karn Agrawal
int turnNumber (HunterView hv){
    return (strlen(hv->pastPlays)+1)/MOVE_STR_LEN;

}

// Frees the HunterView
// Coded by: Karn Agrawal
void disposeHunterView (HunterView toBeDeleted){
    free(toBeDeleted->messages);
    free(toBeDeleted->pastPlays);

    free(toBeDeleted);

}

// Returns an adjacency matrix of the map
// Coded by: Alexander Saunders, Shivanth Radhakrishnan
// Tested by: Karn Agrawal
void giveGraph (HunterView hv, Connection** graph){
    // Instead of hardcoding the numbers into the graph, we should be making
    // calls to locationCode, then it becomes easier to verify correctness and
    // maintain.
    // The graph needs to be initialised to 0 before connections are added,
    // otherwise we get garbage
    // We only need to put down the rail links of length 1, after that we can
    // BFS for all others

    int f, j;
    for (f = 0; f <= SEA_END; f++){
    	for (j = 0; j <= SEA_END; j++){
    		graph[f][j]->rail = 0;
    		graph[f][j]->sea = 0;
    		graph[f][j]->road = 0;
    	}
    }

    //Alicante
    graph[locationCode("AL")][locationCode("BA")]->rail = 1;
    graph[locationCode("AL")][locationCode("MS")]->sea = 1;
    graph[locationCode("AL")][locationCode("SR")]->road = 1;
    graph[locationCode("AL")][locationCode("MA")]->road = 1;
    graph[locationCode("AL")][locationCode("MA")]->rail = 1;
    graph[locationCode("AL")][locationCode("GR")]->road = 1;

    //Amsterdam
    graph[locationCode("AM")][locationCode("BU")]->road = 1;
    graph[locationCode("AM")][locationCode("CO")]->road = 1;
    graph[locationCode("AM")][locationCode("NS")]->sea = 1;

    //Athens
    graph[locationCode("AT")][locationCode("VA")]->road = 1;
    graph[locationCode("AT")][locationCode("IO")]->sea = 1;

    //Barcelona
    graph[locationCode("BA")][locationCode("AL")]->rail = 1;
    graph[locationCode("BA")][locationCode("SR")]->rail = 1;
    graph[locationCode("BA")][locationCode("SR")]->road = 1;
    graph[locationCode("BA")][locationCode("TO")]->road = 1;
    graph[locationCode("BA")][locationCode("MS")]->sea = 1;

    //Bari
    graph[locationCode("BI")][locationCode("NP")]->road = 1;
    graph[locationCode("BI")][locationCode("NP")]->rail = 1;
    graph[locationCode("BI")][locationCode("RO")]->road = 1;
    graph[locationCode("BI")][locationCode("AS")]->sea = 1;

    //Belgrade
    graph[locationCode("BE")][locationCode("SJ")]->road = 1;
    graph[locationCode("BE")][locationCode("JM")]->road = 1;
    graph[locationCode("BE")][locationCode("SZ")]->road = 1;
    graph[locationCode("BE")][locationCode("SZ")]->rail = 1;
    graph[locationCode("BE")][locationCode("KL")]->road = 1;
    graph[locationCode("BE")][locationCode("BC")]->road = 1;
    graph[locationCode("BE")][locationCode("SO")]->road = 1;
    graph[locationCode("BE")][locationCode("SO")]->rail = 1;

    //Berlin
    graph[locationCode("BR")][locationCode("HA")]->road = 1;
    graph[locationCode("BR")][locationCode("HA")]->rail = 1;
    graph[locationCode("BR")][locationCode("LI")]->road = 1;
    graph[locationCode("BR")][locationCode("LI")]->rail = 1;
    graph[locationCode("BR")][locationCode("PR")]->road = 1;
    graph[locationCode("BR")][locationCode("PR")]->rail = 1;

    //Bordeaux
    graph[locationCode("BO")][locationCode("SR")]->rail = 1;
    graph[locationCode("BO")][locationCode("SR")]->road = 1;
    graph[locationCode("BO")][locationCode("TO")]->road = 1;
    graph[locationCode("BO")][locationCode("CF")]->road = 1;
    graph[locationCode("BO")][locationCode("PA")]->rail = 1;
    graph[locationCode("BO")][locationCode("NA")]->road = 1;
    graph[locationCode("BO")][locationCode("BB")]->sea = 1;

    //Brussels
    graph[locationCode("BU")][locationCode("AM")]->road = 1;
    graph[locationCode("BU")][locationCode("CO")]->road = 1;
    graph[locationCode("BU")][locationCode("CO")]->rail = 1;
    graph[locationCode("BU")][locationCode("ST")]->road = 1;
    graph[locationCode("BU")][locationCode("PA")]->rail = 1;
    graph[locationCode("BU")][locationCode("PA")]->road = 1;
    graph[locationCode("BU")][locationCode("LE")]->road = 1;

    //Bucharest
    graph[locationCode("BC")][locationCode("CN")]->road = 1;
    graph[locationCode("BC")][locationCode("CN")]->rail = 1;
    graph[locationCode("BC")][locationCode("GA")]->road = 1;
    graph[locationCode("BC")][locationCode("GA")]->rail = 1;
    graph[locationCode("BC")][locationCode("KL")]->road = 1;
    graph[locationCode("BC")][locationCode("SZ")]->rail = 1;
    graph[locationCode("BC")][locationCode("BE")]->road = 1;
    graph[locationCode("BC")][locationCode("SO")]->road = 1;

    //Budapest
    graph[locationCode("BD")][locationCode("KL")]->road = 1;
    graph[locationCode("BD")][locationCode("SZ")]->road = 1;
    graph[locationCode("BD")][locationCode("SZ")]->rail = 1;
    graph[locationCode("BD")][locationCode("ZA")]->road = 1;
    graph[locationCode("BD")][locationCode("VI")]->road = 1;
    graph[locationCode("BD")][locationCode("VI")]->rail = 1;

    //Cadiz
    graph[locationCode("CA")][locationCode("AO")]->sea = 1;
    graph[locationCode("CA")][locationCode("GR")]->road = 1;
    graph[locationCode("CA")][locationCode("MA")]->road = 1;
    graph[locationCode("CA")][locationCode("LS")]->road = 1;

    //Cagliari 
    graph[locationCode("CG")][locationCode("MS")]->sea = 1;
    graph[locationCode("CG")][locationCode("TS")]->sea = 1;

    //Castle Dracula
    graph[locationCode("CD")][locationCode("GA")]->road = 1;
    graph[locationCode("CD")][locationCode("KL")]->road = 1;

    //Clermont Ferrand
    graph[locationCode("CF")][locationCode("MR")]->road = 1;
    graph[locationCode("CF")][locationCode("GE")]->road = 1;
    graph[locationCode("CF")][locationCode("PA")]->road = 1;
    graph[locationCode("CF")][locationCode("NA")]->road = 1;
    graph[locationCode("CF")][locationCode("BO")]->road = 1;
    graph[locationCode("CF")][locationCode("TO")]->road = 1;

    //Cologne
    graph[locationCode("CO")][locationCode("FR")]->road = 1;
    graph[locationCode("CO")][locationCode("FR")]->rail = 1;
    graph[locationCode("CO")][locationCode("LI")]->road = 1;
    graph[locationCode("CO")][locationCode("HA")]->road = 1;
    graph[locationCode("CO")][locationCode("AM")]->road = 1;
    graph[locationCode("CO")][locationCode("BU")]->road = 1;
    graph[locationCode("CO")][locationCode("BU")]->rail = 1;
    graph[locationCode("CO")][locationCode("ST")]->road = 1;

    //Constanta
    graph[locationCode("CN")][locationCode("GA")]->road = 1;
    graph[locationCode("CN")][locationCode("BC")]->road = 1;
    graph[locationCode("CN")][locationCode("BC")]->rail = 1;
    graph[locationCode("CN")][locationCode("VR")]->road = 1;
    graph[locationCode("CN")][locationCode("BS")]->sea = 1;

    //Dublin
    graph[locationCode("DU")][locationCode("GW")]->road = 1;
    graph[locationCode("DU")][locationCode("IS")]->sea = 1;

    //Edinburgh
    graph[locationCode("ED")][locationCode("MN")]->road = 1;
    graph[locationCode("ED")][locationCode("MN")]->rail = 1;
    graph[locationCode("ED")][locationCode("NS")]->sea = 1;

    //Florence
    graph[locationCode("FL")][locationCode("VE")]->road = 1;
    graph[locationCode("FL")][locationCode("MI")]->rail = 1;
    graph[locationCode("FL")][locationCode("GO")]->road = 1;
    graph[locationCode("FL")][locationCode("RO")]->road = 1;
    graph[locationCode("FL")][locationCode("RO")]->rail = 1;

    //Frankfurt
    graph[locationCode("FR")][locationCode("NU")]->road = 1;
    graph[locationCode("FR")][locationCode("LI")]->road = 1;
    graph[locationCode("FR")][locationCode("LI")]->rail = 1;
    graph[locationCode("FR")][locationCode("CO")]->road = 1;
    graph[locationCode("FR")][locationCode("CO")]->rail = 1;
    graph[locationCode("FR")][locationCode("ST")]->road = 1;
    graph[locationCode("FR")][locationCode("ST")]->rail = 1;

    //Galatz
    graph[locationCode("GA")][locationCode("CD")]->road = 1;
    graph[locationCode("GA")][locationCode("CN")]->road = 1;
    graph[locationCode("GA")][locationCode("BC")]->road = 1; // was broken
    graph[locationCode("GA")][locationCode("BC")]->rail = 1;
    graph[locationCode("GA")][locationCode("KL")]->road = 1;

    //Galway
    graph[locationCode("GW")][locationCode("AO")]->sea = 1;
    graph[locationCode("GW")][locationCode("DU")]->road = 1;

    //Geneva
    graph[locationCode("GE")][locationCode("ZU")]->road = 1;
    graph[locationCode("GE")][locationCode("MI")]->rail = 1;
    graph[locationCode("GE")][locationCode("MR")]->road = 1;
    graph[locationCode("GE")][locationCode("CF")]->road = 1;
    graph[locationCode("GE")][locationCode("PA")]->road = 1;
    graph[locationCode("GE")][locationCode("ST")]->road = 1;

    //Genoa
    graph[locationCode("GO")][locationCode("VE")]->road = 1;
    graph[locationCode("GO")][locationCode("FL")]->road = 1;
    graph[locationCode("GO")][locationCode("MR")]->road = 1;
    graph[locationCode("GO")][locationCode("MI")]->road = 1;
    graph[locationCode("GO")][locationCode("MI")]->rail = 1; // added
    graph[locationCode("GO")][locationCode("TS")]->sea = 1;

    //Granada
    graph[locationCode("GR")][locationCode("AL")]->road = 1;
    graph[locationCode("GR")][locationCode("MA")]->road = 1;
    graph[locationCode("GR")][locationCode("CA")]->road = 1;
    														 // grenada does not connect to sea

    //Hamburg
    graph[locationCode("HA")][locationCode("BR")]->road = 1;
    graph[locationCode("HA")][locationCode("BR")]->rail = 1;
    graph[locationCode("HA")][locationCode("LI")]->road = 1;
    graph[locationCode("HA")][locationCode("CO")]->road = 1;
    graph[locationCode("HA")][locationCode("NS")]->sea = 1;

    //St Joseph & St Mary's
    graph[locationCode("JM")][locationCode("SZ")]->road = 1;
    graph[locationCode("JM")][locationCode("BE")]->road = 1;
    graph[locationCode("JM")][locationCode("SJ")]->road = 1;
    graph[locationCode("JM")][locationCode("ZA")]->road = 1;

    //Klausenburg
    graph[locationCode("KL")][locationCode("CD")]->road = 1;
    graph[locationCode("KL")][locationCode("GA")]->road = 1;
    graph[locationCode("KL")][locationCode("BC")]->road = 1;
    graph[locationCode("KL")][locationCode("BE")]->road = 1;
    graph[locationCode("KL")][locationCode("SZ")]->road = 1;
    graph[locationCode("KL")][locationCode("BD")]->road = 1;

    //Le Havre
    graph[locationCode("LE")][locationCode("PA")]->road = 1;
    graph[locationCode("LE")][locationCode("PA")]->rail = 1;
    graph[locationCode("LE")][locationCode("NA")]->road = 1;
    graph[locationCode("LE")][locationCode("BU")]->road = 1;
    graph[locationCode("LE")][locationCode("EC")]->sea = 1;

    //Leipzig
    graph[locationCode("LI")][locationCode("BR")]->road = 1;
    graph[locationCode("LI")][locationCode("BR")]->rail = 1;
    graph[locationCode("LI")][locationCode("HA")]->road = 1;
    graph[locationCode("LI")][locationCode("CO")]->road = 1;
    graph[locationCode("LI")][locationCode("FR")]->road = 1;
    graph[locationCode("LI")][locationCode("FR")]->rail = 1;
    graph[locationCode("LI")][locationCode("NU")]->road = 1;
    graph[locationCode("LI")][locationCode("NU")]->rail = 1;

    //Lisbon
    graph[locationCode("LS")][locationCode("SN")]->road = 1;
    graph[locationCode("LS")][locationCode("CA")]->road = 1;
    graph[locationCode("LS")][locationCode("MA")]->road = 1;
    graph[locationCode("LS")][locationCode("MA")]->rail = 1;
    graph[locationCode("LS")][locationCode("AO")]->sea = 1; // wasn't here

    //Liverpool
    graph[locationCode("LV")][locationCode("MN")]->road = 1;
    graph[locationCode("LV")][locationCode("MN")]->rail = 1;
    graph[locationCode("LV")][locationCode("SW")]->road = 1;
    graph[locationCode("LV")][locationCode("IS")]->sea = 1;

    //London
    graph[locationCode("LO")][locationCode("MN")]->road = 1;
    graph[locationCode("LO")][locationCode("MN")]->rail = 1;
    graph[locationCode("LO")][locationCode("SW")]->road = 1;
    graph[locationCode("LO")][locationCode("SW")]->rail = 1;
    graph[locationCode("LO")][locationCode("PL")]->road = 1;
    graph[locationCode("LO")][locationCode("EC")]->sea = 1;

    //Madrid
    graph[locationCode("MA")][locationCode("LS")]->road = 1;
    graph[locationCode("MA")][locationCode("LS")]->rail = 1;
    graph[locationCode("MA")][locationCode("CA")]->road = 1;
    graph[locationCode("MA")][locationCode("GR")]->road = 1;
    graph[locationCode("MA")][locationCode("AL")]->road = 1;
    graph[locationCode("MA")][locationCode("AL")]->rail = 1;
    graph[locationCode("MA")][locationCode("SR")]->road = 1;
    graph[locationCode("MA")][locationCode("SR")]->rail = 1;
    graph[locationCode("MA")][locationCode("SN")]->road = 1;
    graph[locationCode("MA")][locationCode("SN")]->rail = 1;

    //Manchester
    graph[locationCode("MN")][locationCode("ED")]->road = 1;
    graph[locationCode("MN")][locationCode("ED")]->rail = 1;
    graph[locationCode("MN")][locationCode("LV")]->road = 1;
    graph[locationCode("MN")][locationCode("LV")]->rail = 1;
    graph[locationCode("MN")][locationCode("LO")]->road = 1;
    graph[locationCode("MN")][locationCode("LO")]->rail = 1;

    //Marseilles
    graph[locationCode("MR")][locationCode("GO")]->road = 1;
    graph[locationCode("MR")][locationCode("MI")]->road = 1;
    graph[locationCode("MR")][locationCode("ZU")]->road = 1;
    graph[locationCode("MR")][locationCode("GE")]->road = 1;
    graph[locationCode("MR")][locationCode("CF")]->road = 1;
    graph[locationCode("MR")][locationCode("PA")]->rail = 1;
    graph[locationCode("MR")][locationCode("TO")]->road = 1;
    graph[locationCode("MR")][locationCode("MS")]->sea = 1;

    //Milan
    graph[locationCode("MI")][locationCode("MR")]->road = 1;
    graph[locationCode("MI")][locationCode("GE")]->rail = 1;
    graph[locationCode("MI")][locationCode("ZU")]->road = 1;
    graph[locationCode("MI")][locationCode("ZU")]->rail = 1;
    graph[locationCode("MI")][locationCode("MU")]->road = 1;
    graph[locationCode("MI")][locationCode("VE")]->road = 1;
    graph[locationCode("MI")][locationCode("FL")]->rail = 1; // wasn't here
    graph[locationCode("MI")][locationCode("GO")]->road = 1; // wasn't here
    graph[locationCode("MI")][locationCode("GO")]->rail = 1; // wasn't here
    
    //Munich
    graph[locationCode("MU")][locationCode("VI")]->road = 1;
    graph[locationCode("MU")][locationCode("VE")]->road = 1;
    graph[locationCode("MU")][locationCode("MI")]->road = 1;
    graph[locationCode("MU")][locationCode("ZU")]->road = 1;
    graph[locationCode("MU")][locationCode("ST")]->road = 1;
    graph[locationCode("MU")][locationCode("NU")]->road = 1;
    graph[locationCode("MU")][locationCode("ZA")]->road = 1; // wasn't here
    graph[locationCode("MU")][locationCode("NU")]->rail = 1;

    //Nantes
    graph[locationCode("NA")][locationCode("LE")]->road = 1;
    graph[locationCode("NA")][locationCode("PA")]->road = 1;
    graph[locationCode("NA")][locationCode("CF")]->road = 1;
    graph[locationCode("NA")][locationCode("BO")]->road = 1;
    graph[locationCode("NA")][locationCode("BB")]->sea = 1;

    //Naples
    graph[locationCode("NP")][locationCode("BI")]->road = 1;
    graph[locationCode("NP")][locationCode("BI")]->rail = 1;
    graph[locationCode("NP")][locationCode("RO")]->road = 1;
    graph[locationCode("NP")][locationCode("RO")]->rail = 1;
    graph[locationCode("NP")][locationCode("TS")]->sea = 1;

    //Nuremburg
    graph[locationCode("NU")][locationCode("MU")]->road = 1;
    graph[locationCode("NU")][locationCode("MU")]->rail = 1;
    graph[locationCode("NU")][locationCode("PR")]->road = 1;
    graph[locationCode("NU")][locationCode("LI")]->road = 1;
    graph[locationCode("NU")][locationCode("LI")]->rail = 1;
    graph[locationCode("NU")][locationCode("FR")]->road = 1;
    graph[locationCode("NU")][locationCode("ST")]->road = 1;

    //Paris
    graph[locationCode("PA")][locationCode("ST")]->road = 1;
    graph[locationCode("PA")][locationCode("BU")]->road = 1;
    graph[locationCode("PA")][locationCode("BU")]->rail = 1;
    graph[locationCode("PA")][locationCode("LE")]->rail = 1;
    graph[locationCode("PA")][locationCode("LE")]->road = 1;
    graph[locationCode("PA")][locationCode("NA")]->road = 1;
    graph[locationCode("PA")][locationCode("BO")]->rail = 1;
    graph[locationCode("PA")][locationCode("CF")]->road = 1;
    graph[locationCode("PA")][locationCode("MR")]->rail = 1;
    graph[locationCode("PA")][locationCode("GE")]->road = 1;

    //Plymouth
    graph[locationCode("PL")][locationCode("LO")]->road = 1;
    graph[locationCode("PL")][locationCode("EC")]->sea = 1;

    //Prague
    graph[locationCode("PR")][locationCode("BR")]->road = 1;
    graph[locationCode("PR")][locationCode("BR")]->rail = 1;
    graph[locationCode("PR")][locationCode("NU")]->road = 1;
    graph[locationCode("PR")][locationCode("VI")]->road = 1;
    graph[locationCode("PR")][locationCode("VI")]->rail = 1;

    //Rome
    graph[locationCode("RO")][locationCode("BI")]->road = 1;
    graph[locationCode("RO")][locationCode("NP")]->road = 1;
    graph[locationCode("RO")][locationCode("NP")]->rail = 1;
    graph[locationCode("RO")][locationCode("FL")]->road = 1;
    graph[locationCode("RO")][locationCode("FL")]->rail = 1;
    graph[locationCode("RO")][locationCode("TS")]->sea = 1;

    //Salonica
    graph[locationCode("SA")][locationCode("SO")]->road = 1;
    graph[locationCode("SA")][locationCode("SO")]->rail = 1;
    graph[locationCode("SA")][locationCode("VA")]->road = 1;
    graph[locationCode("SA")][locationCode("IO")]->sea = 1;

    //Santander
    graph[locationCode("SN")][locationCode("SR")]->road = 1;
    graph[locationCode("SN")][locationCode("MA")]->road = 1;
    graph[locationCode("SN")][locationCode("MA")]->rail = 1; // was wrong
    graph[locationCode("SN")][locationCode("LS")]->road = 1;
    graph[locationCode("SN")][locationCode("BB")]->sea = 1;

    //Saragossa
    graph[locationCode("SR")][locationCode("TO")]->road = 1;
    graph[locationCode("SR")][locationCode("BO")]->road = 1;
    graph[locationCode("SR")][locationCode("BO")]->rail = 1;
    graph[locationCode("SR")][locationCode("SN")]->road = 1;
    graph[locationCode("SR")][locationCode("MA")]->road = 1;
    graph[locationCode("SR")][locationCode("MA")]->rail = 1;
    graph[locationCode("SR")][locationCode("AL")]->road = 1;
    graph[locationCode("SR")][locationCode("BA")]->road = 1;
    graph[locationCode("SR")][locationCode("BA")]->rail = 1;

    //Sarajevo
    graph[locationCode("SJ")][locationCode("VA")]->road = 1;
    graph[locationCode("SJ")][locationCode("SO")]->road = 1;
    graph[locationCode("SJ")][locationCode("BE")]->road = 1;
    graph[locationCode("SJ")][locationCode("JM")]->road = 1;
    graph[locationCode("SJ")][locationCode("ZA")]->road = 1;

    //Sofia
    graph[locationCode("SO")][locationCode("VR")]->road = 1;
    graph[locationCode("SO")][locationCode("VR")]->rail = 1;
    graph[locationCode("SO")][locationCode("BC")]->road = 1;
    graph[locationCode("SO")][locationCode("BE")]->road = 1;
    graph[locationCode("SO")][locationCode("BE")]->rail = 1;
    graph[locationCode("SO")][locationCode("SJ")]->road = 1;
    graph[locationCode("SO")][locationCode("VA")]->road = 1;
    graph[locationCode("SO")][locationCode("SA")]->road = 1;
    graph[locationCode("SO")][locationCode("SA")]->rail = 1;

    //Strasbourg
    graph[locationCode("ST")][locationCode("MU")]->road = 1;
    graph[locationCode("ST")][locationCode("NU")]->road = 1;
    graph[locationCode("ST")][locationCode("FR")]->road = 1;
    graph[locationCode("ST")][locationCode("FR")]->rail = 1;
    graph[locationCode("ST")][locationCode("CO")]->road = 1;
    graph[locationCode("ST")][locationCode("BU")]->road = 1;
    graph[locationCode("ST")][locationCode("PA")]->road = 1;
    graph[locationCode("ST")][locationCode("GE")]->road = 1;
    graph[locationCode("ST")][locationCode("ZU")]->road = 1;
    graph[locationCode("ST")][locationCode("ZU")]->rail = 1;

    //Swansea
    graph[locationCode("SW")][locationCode("LV")]->road = 1;
    graph[locationCode("SW")][locationCode("LO")]->road = 1;
    graph[locationCode("SW")][locationCode("LO")]->rail = 1;
    graph[locationCode("SW")][locationCode("IS")]->sea = 1;

    //Szeged
    graph[locationCode("SZ")][locationCode("BE")]->road = 1;
    graph[locationCode("SZ")][locationCode("BE")]->rail = 1;
    graph[locationCode("SZ")][locationCode("BC")]->rail = 1;
    graph[locationCode("SZ")][locationCode("KL")]->road = 1;
    graph[locationCode("SZ")][locationCode("BD")]->road = 1;
    graph[locationCode("SZ")][locationCode("BD")]->rail = 1;
    graph[locationCode("SZ")][locationCode("ZA")]->road = 1;
    graph[locationCode("SZ")][locationCode("JM")]->road = 1;

    //Toulouse
    graph[locationCode("TO")][locationCode("CF")]->road = 1;
    graph[locationCode("TO")][locationCode("MR")]->road = 1;
    graph[locationCode("TO")][locationCode("BA")]->road = 1;
    graph[locationCode("TO")][locationCode("BO")]->road = 1;
    graph[locationCode("TO")][locationCode("SR")]->road = 1;

    //Valona
    graph[locationCode("VA")][locationCode("AT")]->road = 1;
    graph[locationCode("VA")][locationCode("SA")]->road = 1;
    graph[locationCode("VA")][locationCode("SO")]->road = 1;
    graph[locationCode("VA")][locationCode("SJ")]->road = 1;
    graph[locationCode("VA")][locationCode("IO")]->sea = 1;

    //Varna
    graph[locationCode("VR")][locationCode("CN")]->road = 1;
    graph[locationCode("VR")][locationCode("SO")]->road = 1;
    graph[locationCode("VR")][locationCode("SO")]->rail = 1;
    graph[locationCode("VR")][locationCode("BS")]->sea = 1;

    //Venice
    graph[locationCode("VE")][locationCode("VI")]->rail = 1;
    graph[locationCode("VE")][locationCode("MU")]->road = 1;
    graph[locationCode("VE")][locationCode("MI")]->road = 1;
    graph[locationCode("VE")][locationCode("GO")]->road = 1;
    graph[locationCode("VE")][locationCode("FL")]->road = 1;
    graph[locationCode("VE")][locationCode("AS")]->sea = 1;

    //Vienna
    graph[locationCode("VI")][locationCode("BD")]->road = 1;
    graph[locationCode("VI")][locationCode("BD")]->rail = 1;
    graph[locationCode("VI")][locationCode("PR")]->road = 1;
    graph[locationCode("VI")][locationCode("PR")]->rail = 1;
    graph[locationCode("VI")][locationCode("MU")]->road = 1;
    graph[locationCode("VI")][locationCode("VE")]->rail = 1;
    graph[locationCode("VI")][locationCode("ZA")]->road = 1;

    //Zagreb
    graph[locationCode("ZA")][locationCode("BD")]->road = 1;
    graph[locationCode("ZA")][locationCode("VI")]->road = 1;
    graph[locationCode("ZA")][locationCode("MU")]->road = 1;
    graph[locationCode("ZA")][locationCode("SJ")]->road = 1;
    graph[locationCode("ZA")][locationCode("JM")]->road = 1;
    graph[locationCode("ZA")][locationCode("SZ")]->road = 1;

    //Zurich
    graph[locationCode("ZU")][locationCode("MU")]->road = 1;
    graph[locationCode("ZU")][locationCode("ST")]->road = 1;
    graph[locationCode("ZU")][locationCode("ST")]->rail = 1;
    graph[locationCode("ZU")][locationCode("GE")]->road = 1;
    graph[locationCode("ZU")][locationCode("MR")]->road = 1;
    graph[locationCode("ZU")][locationCode("MI")]->road = 1;
    graph[locationCode("ZU")][locationCode("MI")]->rail = 1;

    //North Sea
    graph[locationCode("NS")][locationCode("AM")]->sea = 1;
    graph[locationCode("NS")][locationCode("HA")]->sea = 1;
    graph[locationCode("NS")][locationCode("ED")]->sea = 1;
    graph[locationCode("NS")][locationCode("EC")]->sea = 1;
    graph[locationCode("NS")][locationCode("AO")]->sea = 1;

    //English Channel
    graph[locationCode("EC")][locationCode("LO")]->sea = 1;
    graph[locationCode("EC")][locationCode("PL")]->sea = 1;
    graph[locationCode("EC")][locationCode("LE")]->sea = 1;
    graph[locationCode("EC")][locationCode("NS")]->sea = 1;
    graph[locationCode("EC")][locationCode("AO")]->sea = 1;

    //Irish Sea
    graph[locationCode("IS")][locationCode("DU")]->sea = 1;
    graph[locationCode("IS")][locationCode("LV")]->sea = 1;
    graph[locationCode("IS")][locationCode("SW")]->sea = 1;
    graph[locationCode("IS")][locationCode("AO")]->sea = 1;

    //Atlantic Ocean
    graph[locationCode("AO")][locationCode("GW")]->sea = 1;
    graph[locationCode("AO")][locationCode("LS")]->sea = 1;
    graph[locationCode("AO")][locationCode("CA")]->sea = 1;
    graph[locationCode("AO")][locationCode("BB")]->sea = 1;
    graph[locationCode("AO")][locationCode("IS")]->sea = 1;
    graph[locationCode("AO")][locationCode("MS")]->sea = 1;
    graph[locationCode("AO")][locationCode("EC")]->sea = 1;
    graph[locationCode("AO")][locationCode("NS")]->sea = 1;

    //Bay of Biscay
    graph[locationCode("BB")][locationCode("NA")]->sea = 1;
    graph[locationCode("BB")][locationCode("BO")]->sea = 1;
    graph[locationCode("BB")][locationCode("SN")]->sea = 1;
    graph[locationCode("BB")][locationCode("AO")]->sea = 1;

    //Mediterranean Sea
    graph[locationCode("MS")][locationCode("AL")]->sea = 1;
    graph[locationCode("MS")][locationCode("BA")]->sea = 1;
    graph[locationCode("MS")][locationCode("MR")]->sea = 1;
    graph[locationCode("MS")][locationCode("CG")]->sea = 1;
    graph[locationCode("MS")][locationCode("TS")]->sea = 1;
    graph[locationCode("MS")][locationCode("AO")]->sea = 1;

    //Tyrrhenian Sea
    graph[locationCode("TS")][locationCode("GO")]->sea = 1;
    graph[locationCode("TS")][locationCode("RO")]->sea = 1;
    graph[locationCode("TS")][locationCode("NP")]->sea = 1;
    graph[locationCode("TS")][locationCode("MS")]->sea = 1;
    graph[locationCode("TS")][locationCode("IO")]->sea = 1;
    graph[locationCode("TS")][locationCode("CG")]->sea = 1; // wasn't here

    //Ionian Sea
    graph[locationCode("IO")][locationCode("VA")]->sea = 1;
    graph[locationCode("IO")][locationCode("AT")]->sea = 1;
    graph[locationCode("IO")][locationCode("SA")]->sea = 1;
    graph[locationCode("IO")][locationCode("AS")]->sea = 1;
    graph[locationCode("IO")][locationCode("TS")]->sea = 1;
    														// black sea and is aren't connected

    //Adriatic Sea
    graph[locationCode("AS")][locationCode("BI")]->sea = 1;
    graph[locationCode("AS")][locationCode("VE")]->sea = 1;
    graph[locationCode("AS")][locationCode("IO")]->sea = 1;

    //Black Sea
    graph[locationCode("BS")][locationCode("CN")]->sea = 1;
    graph[locationCode("BS")][locationCode("VR")]->sea = 1;
    														// black sea and IS aren't connected
    
    for (f = 0; f <= SEA_END; f++){
        railBFS(graph, f);
    }
}

// Gives the two character location code of a desired move
// Coded by: Alexander Saunders, Shivanth Radhakrishnan
// Tested by: Karn Agrawal
void getMoveCode (char *move, int location){
    char* cities[NUM_LOCATIONS];
    populateLocationCodes(cities);
    strcpy(move,cities[location]);
}

// Gives the integer corresponding to a location code
// Returns -1 if city code does not exist
// Coded by: Alexander Saunders, Shivanth Radhakrishnan
// Tested by: Karn Agrawal
int locationCode(char *str){
    char* cities[NUM_LOCATIONS];
    int counter = 0;
    int retval = -1;

    populateLocationCodes(cities);

    //Time to do a linear search because its easy and to my dismay
    //The city codes aren't in alphabetical order :(
    while (counter < NUM_LOCATIONS) {
        if (strncmp(cities[counter], str, 2) == 0) {
            retval = counter;
            counter = NUM_LOCATIONS;
        }
        counter++;
    }
    return retval;
}

// Returns the number of moves Dracula has made
// Coded by: Daniel Chen, Robert Newey
int numDraculaMoves (HunterView hv){
    int f;
    int numMoves = turnNumber(hv);
    int dracMoves = 0;

    for (f = 0; f < numMoves; f++){
        if (playerNumber(hv->pastPlays[f*MOVE_STR_LEN]) == DRACULA){
            dracMoves++;
        }
    }
    return dracMoves;
}

// Returns Dracula's current health
// Coded by: Daniel Chen, Robert Newey
int draculaHealth (HunterView hv){
    int f, j;
    int numMoves = turnNumber(hv);
    int health = DRAC_INIT;
    int targetPlayer;
    char location[3];
    int locationNum;
    char seas[NUM_SEAS][3] = {"NS", "EC", "IS", "AO", "BB", "MS", "TS", "IO",
                              "AS", "BS", "S?"};
    char castle[2][3] = {"TP", "CD"};

    for (f = 0; f < numMoves; f++){
        targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
        if (targetPlayer == DRACULA){
            location[0] = hv->pastPlays[f*MOVE_STR_LEN+1];
            location[1] = hv->pastPlays[f*MOVE_STR_LEN+2];
            location[2] = '\0';
            locationNum = locationCode (location);

            for (j = 0; j < NUM_SEAS; j++){
                if (locationCode (seas[j]) == locationNum){
                    health += DRAC_SEA;
                }
            }

            for (j = 0; j < 2; j++){
                if (locationCode (castle[j]) == locationNum){
                    health += DRAC_CASTLE;
                }
            }
        } else {
            for (j = 0; j < NUM_ENCOUNTERS; j++){
                if (hv->pastPlays[f*MOVE_STR_LEN+3+j] == ENCOUNTER_DRACULA){
                    health += DRAC_FOUND;
                }
            }
        }
    }
    return health;
}

// Returns all the information about dracula's moves
// Coded by: Daniel Chen, Robert Newey
void draculaMoves (HunterView hv, int *moves){
    int f;
    int numMoves = turnNumber(hv);
    int targetPlayer;
    char location[3];
    int draculaMovesMade = 0;

    for (f = 0; f < numMoves; f++){
        targetPlayer = playerNumber (hv->pastPlays[f*MOVE_STR_LEN]);
        if (targetPlayer == DRACULA){
            location[0] = hv->pastPlays[f*MOVE_STR_LEN+1];
            location[1] = hv->pastPlays[f*MOVE_STR_LEN+2];
            location[2] = '\0';
            moves[draculaMovesMade] = locationCode(location);
            draculaMovesMade++;
        }
    }
}

///////////////////////////////////////////
/////         Helper functions        /////
///////////////////////////////////////////

int playerNumber(char name){
    int retval;
    switch (name){
        case 'G':
            retval = GODALMING;
            break;
        case 'S':
            retval = SEWARD;
            break;
        case 'H':
            retval = HELSING;
            break;
        case 'M':
            retval = MINA;
            break;
        case 'D':
            retval = DRACULA;
            break;
    }
    return retval;
}

void alivePlayers (HunterView hv, int isAlive[]){
    int f;
    int numMoves = turnNumber(hv);
    int currentPlayer = whoAmI (hv);
    int draculaMoveMade = FALSE;
    int targetPlayer;

    for (f = 0; f < NUM_HUNTERS; f++){
        isAlive[f] = FALSE;
    }

    for (f = 0; f < numMoves && !draculaMoveMade; f++){
        targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
        if (targetPlayer == DRACULA){
            draculaMoveMade = TRUE;
        }
    }

    if (draculaMoveMade) {
        f = numMoves-1;
        targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
        while (f >= 0 && targetPlayer != currentPlayer){
            if (targetPlayer != DRACULA){
            	isAlive[targetPlayer] = TRUE;
            }
            f--;
            if (f >= 0){
            	targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
            }
        }
        isAlive[currentPlayer] = TRUE;
    } else {
        // everyone after you is alive, everyone before has to qualify
        for (f = 0; f < numMoves; f++){
            targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
            if (targetPlayer != DRACULA){
            	isAlive[targetPlayer] = TRUE;
            }
        }
        for (f = currentPlayer; f < NUM_HUNTERS; f++){
            isAlive[f] = TRUE;
        }
    }
}

void setLocations (HunterView hv, Move* moves){
    int f;
    int numMoves = turnNumber(hv);
    int targetPlayer;
    int currentPlayer = whoAmI(hv);
    int currentPlayerEncountered = FALSE;
    char location[3];

    for (f = 0; f < NUM_HUNTERS; f++){
        moves[f]->location = YET_TO_MOVE;
    }

    f = numMoves-1;
    targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
    while (f >= 0 && !currentPlayerEncountered){
        if (currentPlayer == targetPlayer){
            currentPlayerEncountered = TRUE;
        }
        if (targetPlayer != DRACULA){
			location[0] = hv->pastPlays[f*MOVE_STR_LEN+1];
			location[1] = hv->pastPlays[f*MOVE_STR_LEN+2];
			location[2] = '\0';
			moves[targetPlayer]->location = locationCode(location);
		}
        f--;
        if (f >= 0){
            targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
        }
    }
}

int checkRested(HunterView hv, int player) {
    int retval;
    int f;
    int numMoves = turnNumber(hv);
    int targetPlayer;
    int target[2];
    int count=0;
    f = numMoves-1;
    char location[3];

    targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
    while (f >= 0 && count <2) {
        if (player == targetPlayer) {
            location[0] = hv->pastPlays[f*MOVE_STR_LEN+1];
            location[1] = hv->pastPlays[f*MOVE_STR_LEN+2];
            location[2] = '\0';
            target[count]=locationCode(location);
            count++;
        }
    f--;
    }
    if (count <2 ) {
        retval = FALSE;
    } else {
        retval = (target[0] == target[1]);
    }

    return retval;
}

int checkHealth(HunterView hv, int player, int *died){
    int f, j;
    int numMoves = turnNumber(hv);
    int targetPlayer;
    int prevLocation = YET_TO_MOVE;
    int currLocation = YET_TO_MOVE;
    int currHealth = HEALTH_INIT;
    char location[3];
    char encounter;

    for (f = 0; f < numMoves; f++){
        targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
        if (targetPlayer == player){
        	*died = FALSE;
            location[0] = hv->pastPlays[f*MOVE_STR_LEN+1];
            location[1] = hv->pastPlays[f*MOVE_STR_LEN+2];
            location[2] = '\0';
            currLocation = locationCode(location);

            for (j = 0; j < NUM_ENCOUNTERS; j++){
                encounter = hv->pastPlays[f*MOVE_STR_LEN+3+j];
                if (encounter == ENCOUNTER_DRACULA){
                    currHealth += HEALTH_DRACULA;
                } else if (encounter == ENCOUNTER_TRAP){
                    currHealth += HEALTH_TRAP;
                }
            }
            if (currHealth < 1){
                *died = TRUE;
                currHealth = HEALTH_INIT;
            }

            if (currLocation == prevLocation){
                currHealth += HEALTH_REST;
            }
            prevLocation = currLocation;

            if (currHealth > HEALTH_INIT){
                currHealth = HEALTH_INIT;
            }
        }
    }

    return currHealth;
}

char *getMessage(HunterView hv, int player){
    char *retval = NULL;
    int f;
    int numMoves = turnNumber(hv);
    int targetPlayer;
    int foundPlayer = FALSE;

    for (f = numMoves - 1; f >= 0 && !foundPlayer; f--){
        targetPlayer = playerNumber(hv->pastPlays[f*MOVE_STR_LEN]);
        if (targetPlayer == player){
            retval = hv->messages[f];
            foundPlayer = TRUE;
        }
    }
    return retval;
}

void populateLocationCodes(char** locations){
    locations[0] = "AL";
    locations[1] = "AM";
    locations[2] = "AT";
    
    locations[3] = "BA";
    locations[4] = "BI";
    locations[5] = "BE";
    locations[6] = "BR";
    locations[7] = "BO";
    locations[8] = "BU";
    locations[9] = "BC";
    locations[10] = "BD";
    
    locations[11] = "CA";
    locations[12] = "CG";
    locations[13] = "CD";
    locations[14] = "CF";
    locations[15] = "CO";
    locations[16] = "CN";
    
    locations[17] = "DU";
    
    locations[18] = "ED";
    
    locations[19] = "FL";
    locations[20] = "FR";
    
    locations[21] = "GA";
    locations[22] = "GW";
    locations[23] = "GE";
    locations[24] = "GO";
    locations[25] = "GR";
    
    locations[26] = "HA";
    
    locations[27] = "JM";
    
    locations[28] = "KL";
    
    locations[29] = "LE";
    locations[30] = "LI";
    locations[31] = "LS";
    locations[32] = "LV";
    locations[33] = "LO";
    
    locations[34] = "MA";
    locations[35] = "MN";
    locations[36] = "MR";
    locations[37] = "MI";
    locations[38] = "MU";
    
    locations[39] = "NA";
    locations[40] = "NP";
    locations[41] = "NU";
    
    locations[42] = "PA";
    locations[43] = "PL";
    locations[44] = "PR";
    
    locations[45] = "RO";
    
    locations[46] = "SA";
    locations[47] = "SN";
    locations[48] = "SR";
    locations[49] = "SJ";
    locations[50] = "SO";
    locations[51] = "ST";
    locations[52] = "SW";
    locations[53] = "SZ";
    
    locations[54] = "TO";
    
    locations[55] = "VA";
    locations[56] = "VR";
    locations[57] = "VE";
    locations[58] = "VI";
    
    locations[59] = "ZA";
    locations[60] = "ZU";
    
    locations[61] = "NS";
    locations[62] = "EC";
    locations[63] = "IS";
    locations[64] = "AO";
    locations[65] = "BB";
    locations[66] = "MS";
    locations[67] = "TS";
    locations[68] = "IO";
    locations[69] = "AS";
    locations[70] = "BS";
    
    locations[71] = "C?";
    locations[72] = "S?";
    locations[73] = "HI";
    locations[74] = "D1";
    locations[75] = "D2";
    locations[76] = "D3";
    locations[77] = "D4";
    locations[78] = "D5";
    locations[79] = "TP";
}

void railBFS(Connection **graph, int point){
	int *dist = malloc(sizeof(int)*100);
	int f, j;
	int depth;
	assert(dist != NULL);
	for (f = 0; f < 100; f++){
	    dist[f] = 0;
	}
	for (f = 0; f <= SEA_END; f++){
	    if (graph[point][f]->rail == 1){
	    	dist[f] = 1;
	    }
	}
	
	for (depth = 2; depth <= 3; depth++){
		for (f = 0; f <= SEA_END; f++){
			if (dist[f] == depth-1){
				for (j = 0; j <= SEA_END; j++){
					if (graph[f][j]->rail == 1 && !dist[j]){
						dist[j] = depth;
					}
				}
			}
		}
	}
	
	for (f = 0; f <= SEA_END; f++){
		graph[f][point]->rail = dist[f];
		graph[point][f]->rail = dist[f];
	}
}



